// nettest.cc 
//	Test out message delivery between two "Nachos" machines,
//	using the Post Office to coordinate delivery.
//
//	Two caveats:
//	  1. Two copies of Nachos must be running, with machine ID's 0 and 1:
//		./nachos -m 0 -o 1 &
//		./nachos -m 1 -o 0 &
//
//	  2. You need an implementation of condition variables,
//	     which is *not* provided as part of the baseline threads 
//	     implementation.  The Post Office won't work without
//	     a correct implementation of condition variables.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

//NOTE:  Each instance of nachos has one network address and each has several mailboxes (10 max)

#include "copyright.h"

#include "../userprog/syscall.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <string>
#include <time.h>
#include <cstring>

#define MAX_LOCKS	5000
#define MAX_CONDS 	5000
#define maxMailSize 39
#define MAX_MONITORS	500
#define MAX_MONITOR_VALUES	100
#define DYH_LOCK 0
#define DYH_CV 1
#define DYH_MV 2
#define DYH_MSG 0
#define DYH_REPLY 1
#define client_mailbox 0
#define server_mailbox 1


// Test out message delivery, by doing the following:
//	1. send a message to the machine with ID "farAddr", at mail box #0
//	2. wait for the other machine's message to arrive (in our mailbox #0)
//	3. send an acknowledgment for the other machine's message
//	4. wait for an acknowledgement from the other machine to our 
//	    original message




struct ServerLock{
string name;
int state; // -1 = deleted/not in use, 0 = available, 1 = busy
int ownerMachineID;
int ownerMailboxNum;
queue<PacketHeader> outgoingMsgPktHdr;
queue<MailHeader> outgoingMsgMailHdr;
	ServerLock(){
		state = -1;
	}
};

struct ServerCV{
string name;
int state;  // -1 = deleted/not in use, 1 = available/in use
int ownerMachineID;
int ownerMailboxNum;
int lockUsed; //index in lock table
queue<PacketHeader> outgoingMsgPktHdr;
queue<MailHeader> outgoingMsgMailHdr;
	ServerCV(){
		state = -1;
		lockUsed = -1;
	}
};

struct ServerMV{
	int monitorValues[MAX_MONITOR_VALUES];
	string name;
	int ownerMachineID;
	int ownerMailboxNum;
	int inUse;
	int curIndex;
	
	ServerMV(){
		inUse = 0;
		curIndex = 0;
	}
};

struct DYH{
	int machineID;
	int mailbox;
	string name;
	int type;
	int call;
	//int response;
	
	DYH(){
		machineID = -1;
		mailbox = -1;
		name = "";
		type = -1;
		call = -1;
		//response = -1;
	}
};

struct PendingRequest{
	string name;
	int identifier; //optional
	int type; //0 for lock, 1 for CV, 2 for MV - use DYH defines
	int numberOfNoReplies;
	char* originalClientMessage; //to forward if needed
	string msg;
	int clientMachineID;
	int clientMailbox;
	timeval myTime; //http://www.delorie.com/gnu/docs/glibc/libc_428.html
	int timestamp;
	queue<DYH> pendingDYH;
	//time_t timestamp;
	
	PendingRequest(){
		numberOfNoReplies = 0;
		gettimeofday(&myTime, NULL);
		//int sec = myTime.tv_sec;
		//int usec = myTime.tv_usec;
		int theTime = (myTime.tv_sec*1000000) + myTime.tv_usec;
		timestamp = theTime;
		//printf("the time %i\n", theTime);
		//printf("the sec %i\n", sec);
		//printf("the usec %i\n", usec);
		//timestamp = time (NULL);
		//printf("time %i\n", timestamp);
		//pendingDYH = new List();
		identifier = -1;
		type = -1;
		numberOfNoReplies = 0;
		originalClientMessage = "";
		clientMachineID = -1;
		clientMailbox = -1;
	}
};

#define MAX_REQUESTS 1500
Lock* pendingRequestLock = new Lock("Pending Request Lock");
PendingRequest pendingRequests[MAX_REQUESTS];
int requestCounter = 0;

// ------------------ GLOBAL VARIABLES ----------------- **	
int serverMachineID = 0; //DEBUG, later this will be set at Server creation
int serverThread1BoxNum = 0;  //DEBUG, later this will be set at Server creation
int serverThread2BoxNum = 1;  //DEBUG, later this will be set at Server creation
ServerLock lockArray[MAX_LOCKS];
Lock* serverLockLock = new Lock("Server Lock Array Lock");
ServerCV condArray[MAX_CONDS];
Lock* serverCVLock = new Lock("Server CV Array Lock");
ServerMV serverMonitorVariables[MAX_MONITORS];
Lock* serverMVLock = new Lock("Server MV Array Lock");
int nextLockIndex = 0;
int nextCondIndex = 0;
int numberOfServers = 1;

int charToInt(char input){
	switch (input){
		case '0':
			return 0;
		case '1':
			return 1;
		case '2':
			return 2;
		case '3':
			return 3;
		case '4':
			return 4;
		case '5':
			return 5;
		case '6':
			return 6;
		case '7':
			return 7;
		case '8':
			return 8;
		case '9':
			return 9;
		default:
			printf("Error, incorrect input to charToInt.\n");
			return -1;
	}
}


void ServerCreateLock(char reply[], string &messageName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerAcquireLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerReleaseLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage, int &needReply);

void ServerDestroyLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerCreateCondition(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerWaitCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerSignalCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerBroadcastCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void ServerDestroyCondition(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void CreateMonitor_Syscall(char reply[], string name, int value, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void DestroyMonitor_Syscall(char reply[], string name, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void GetMonitor_Syscall(char reply[], int pos, string name, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void SetMonitor_Syscall(char reply[], int val, int pos, string name, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage);

void HandleServerThread(int numServers);

int DoIHaveLock(string name){ //returns 1 if you have it, 0 if you don't
	printf("Do I have lock %s?\n", name.c_str());
	serverLockLock->Acquire();
	//printf("seg fault yet? %i\n", MAX_LOCKS);
	for(int i = 0; i < MAX_LOCKS; i++){
		//printf("how about now? %i\n", i);
		if(lockArray[i].name == name){ //lock has been found
			//printf("surely not now...\n");
			serverLockLock->Release();
			//printf("or now?\n");
			return 1;
		}
	}
	serverLockLock->Release();
	return 0;
}

int DoIHaveCV(string name){ //returns 1 if you have it, 0 if you don't
	printf("do I have cv %s?\n", name.c_str());
	serverCVLock->Acquire();
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == name){
			serverCVLock->Release();
			return 1;
		}
	}
	serverCVLock->Release();
	return 0;
}

int DoIHaveMV(string name){ //returns 1 if you have it, 0 if you don't
	printf("do I have mv %s?\n", name.c_str());
	serverMVLock->Acquire();
	for(int i = 0; i < MAX_MONITORS; i++){
		if(serverMonitorVariables[i].name == name){
			serverMVLock->Release();
			return 1;
		}
	}
	serverMVLock->Release();
	return 0;
}

int DoIHaveRequest(int type, int ident, string name){ //ident = call
	printf("do i have the request for %s?\n", name.c_str());
	int result = -1;
	pendingRequestLock->Acquire();
	//printf("we're about to find out!\n");
	for(int i = 0; i < MAX_REQUESTS; i++){
		if(pendingRequests[i].type == type && pendingRequests[i].identifier == ident && pendingRequests[i].name == name){
			//printf("found it! at %i\n", i);
			result = i;
			break;
		}
	}
	pendingRequestLock->Release();
	return result;
}

void updatePendingRequestTable(int type, int ident, string name, char* msg, int machineID, int mailbox){
	pendingRequestLock->Acquire();
	//printf("updating some pending requests, bro\n");
	int requestIndex = -1;
	
	/*for(int i = 0; i < MAX_REQUESTS; i++){
		if(pendingRequests[i].type == type && pendingRequests[i].name == name && pendingRequests[i].identifier == ident){ //found entry, compare timestamps
			printf("yo i found the request already brohan\n");
			//requestIndex = i;
			timeval curTime;
			long curTimestamp;
			gettimeofday(&curTime, NULL);
			curTimestamp = (curTime.tv_sec*1000000) + curTime.tv_usec;
			//printf("**************FOUND %s\n", name.c_str());
			if(curTimestamp < pendingRequests[i].timestamp){
				//pendingRequests[i].timestamp = curTimestamp;
				//after watching lecture, crowley said not to replace the timestamp entries, to have separate ones? not sure what to do...
			}
		}
	}*/
	
	if(requestIndex == -1){ //not in there yet, add entry
		printf("adding entry at %i with message '%s'\n", requestCounter, msg);
		//printf("yo i need to add dat pending request\n");
		pendingRequests[requestCounter].name = name;
		pendingRequests[requestCounter].identifier = ident;
		pendingRequests[requestCounter].type = type;
		pendingRequests[requestCounter].originalClientMessage = msg;
		pendingRequests[requestCounter].msg = msg;
		//printf("MSG: '%s'\n", pendingRequests[requestCounter].msg.c_str());
		pendingRequests[requestCounter].clientMachineID = machineID;
		pendingRequests[requestCounter].clientMailbox = mailbox;
		pendingRequests[requestCounter].numberOfNoReplies = 0;
		
		//time_t john_lennon;
		//john_lennon = time (NULL);
		//pendingRequests[requestCounter].timestamp = john_lennon;
		
		timeval myTime;
		gettimeofday(&myTime, NULL);
		int john_lennon = (myTime.tv_sec*1000000) + myTime.tv_usec;
		pendingRequests[requestCounter].timestamp = john_lennon;
		//printf("john_lennon: %i\n", john_lennon);
		
		//printf("the time is %i\n", john_lennon);
		
		//timeval curTime;
		//long curTimestamp;
		//gettimeofday(&curTime, NULL);
		//curTimestamp = (curTime.tv_sec*1000000) + curTime.tv_usec;
		//pendingRequests[requestCounter].timestamp = curTimestamp;
		
		//printf("the timestamp is %i\n", curTimestamp);
		
		requestCounter++;
	}
	
	pendingRequestLock->Release();
}

void clearPendingRequestEntry(int index){
	printf("clearing pending request entry %i\n", index);
	pendingRequestLock->Acquire();
	
	pendingRequests[index].name = "";
	pendingRequests[index].identifier = -1;
	pendingRequests[index].type = -1;
	pendingRequests[index].originalClientMessage = "";
	pendingRequests[index].clientMachineID = -1;
	pendingRequests[index].clientMailbox = -1;
	pendingRequests[index].numberOfNoReplies = 0;
	pendingRequests[index].msg = "";
	
	pendingRequestLock->Release();
} 

void DoYouHaveLock(string name, int call){
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	printf("gotta find dat lock!\n");
	for(int i = 0; i < numberOfServers; i++){
		if(i != currentThread->getMachineId()){
			//time_t paul_mccartney;
			//paul_mccartney = time (NULL);
			timeval myTime;
			gettimeofday(&myTime, NULL);
			int paul_mccartney = (myTime.tv_sec*1000000) + myTime.tv_usec;
			//printf("paul_mccartney: %i\n", paul_mccartney);
			char DYH_MESSAGE[MaxMailSize];
			sprintf(DYH_MESSAGE, "%i %i %i %s %i", DYH_MSG, DYH_LOCK, call, name.c_str(), paul_mccartney);
			printf("sending message to machine %i: ", i);
			printf(DYH_MESSAGE);
			printf("\n");
			
			outPktHdr.to = i;
			outPktHdr.from = currentThread->getMachineId();
			outMailHdr.to = server_mailbox;
			outMailHdr.from = server_mailbox;
			outMailHdr.length = strlen(DYH_MESSAGE) + 1;
			
			bool success = postOffice->Send(outPktHdr, outMailHdr, DYH_MESSAGE);
			
			if(!success){
				printf("postOffice send failed in sending DYH for locks\n");
				interrupt->Halt();
			}
		}
	}
}

void DoYouHaveCV(string name, int call){
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	printf("gotta find dat cv!\n");
	for(int i = 0; i < numberOfServers; i++){
		if(i != currentThread->getMachineId()){
			//time_t ringo_starr;
			//ringo_starr = time(NULL);
			
			timeval myTime;
			gettimeofday(&myTime, NULL);
			int ringo_starr = (myTime.tv_sec*1000000) + myTime.tv_usec;
			//printf("ringo_starr: %i\n", ringo_starr);
			char DYH_MESSAGE[MaxMailSize];
			sprintf(DYH_MESSAGE, "%i %i %i %s %i", DYH_MSG, DYH_CV, call, name.c_str(), ringo_starr);
			printf("sending message to machine %i: ", i);
			printf(DYH_MESSAGE);
			printf("\n");
			
			outPktHdr.to = i;
			outPktHdr.from = currentThread->getMachineId();
			outMailHdr.to = server_mailbox;
			outMailHdr.from = server_mailbox;
			outMailHdr.length = strlen(DYH_MESSAGE) + 1;
			
			bool success = postOffice->Send(outPktHdr, outMailHdr, DYH_MESSAGE);
			
			if(!success){
				printf("postOffice send failed in sending DYH for CVs\n");
				interrupt->Halt();
			}
		}
	}
}

void DoYouHaveMV(string name, int call){
	PacketHeader outPktHdr;
	MailHeader outMailHdr;
	printf("gotta find dat mv!\n");
	for(int i = 0; i < numberOfServers; i++){
		if(i != currentThread->getMachineId()){
			//time_t george_harrison;
			//george_harrison = time (NULL);
			
			timeval myTime;
			gettimeofday(&myTime, NULL);
			int george_harrison = (myTime.tv_sec*1000000) + myTime.tv_usec;
			//printf("george_harrison: %i\n", george_harrison);
			char DYH_MESSAGE[MaxMailSize];
			sprintf(DYH_MESSAGE, "%i %i %i %s %i", DYH_MSG, DYH_MV, call, name.c_str(), george_harrison);
			printf("sending message to machine %i: ", i);
			printf(DYH_MESSAGE);
			printf("\n");
			
			outPktHdr.to = i;
			outPktHdr.from = currentThread->getMachineId();
			outMailHdr.to = server_mailbox;
			outMailHdr.from = server_mailbox;
			outMailHdr.length = strlen(DYH_MESSAGE) + 1;
			
			bool success = postOffice->Send(outPktHdr, outMailHdr, DYH_MESSAGE);
			
			if(!success){
				printf("postOffice send failed in sending DYH for MVs\n");
				interrupt->Halt();
			}
		}
	}
}

void Server(int numServers){
	ASSERT(numServers > 0);
	ASSERT(numServers <= 5);
	numberOfServers = numServers;
	
	//--------------------------------
	
	bool sendMessageResult;
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
	int callType;
	int shouldSendMessage;
	char *firstMessageValueChar;
	int firstMessageValue;
	char *secondMessageValueChar;
	int secondMessageValue;
	int thirdMessageValue;
	char *messageName;
	string messageString;
    char *data;
    char buffer[maxMailSize];
	char replyMsg[maxMailSize];
	string read1;
	string read2;
	/* incoming message data format:
		0-1		syscall types
		2 		space
		3-6		first value (lock ID or monitor ID)
		7		space
		8-11	second value (cond ID)
		12		space
		13-32	char*
		33 		space
	*/
	/* outgoing message data format:
		0-3		reply value
	*/
	
	//printf("forking the server-server thread\n");
	//currentThread->Fork(HandleServerThread, numServers); //fork the server-server thread
	
	printf("Server is alive!\n\n\n");
	while(true){	
		//printf("machineID = %i\n", currentThread->getMachineId());
		printf("Server: From the top! NextLockIndex: %d  NextCondIndex: %d \n", nextLockIndex, nextCondIndex);
		//time_t curTime = time (NULL);
		//printf("curServerTime = %i\n", curTime);
		for(int k = 0; k < maxMailSize; k++){  //clear char arrays
			buffer[k] = '\0';
			replyMsg[k] = '\0';
		}
		shouldSendMessage = 0;
		
		// ---------- Receive a message
		//printf("about to receive message\n");
		//currentThread->Yield();
		postOffice->Receive(client_mailbox, &inPktHdr, &inMailHdr, buffer);
		//printf("received message\n");
		char* clientMessage = buffer;
		printf("buffer: '%s'\n", buffer);
				
		// ---------- Parse message
		stringstream ss (stringstream::in | stringstream::out);
		callType = 0;
		firstMessageValue = 0;
		secondMessageValue = 0;
		messageString.clear();
		ss.str("");
		ss << buffer;
		printf("Just loaded ss, about to read back: ");
		ss >> callType;
		/*printf("%i ", callType);
		ss >> firstMessageValue;
		printf("%i ", firstMessageValue);
		ss >> secondMessageValue;
		printf("%i ", secondMessageValue);
		if(callType == SC_SetMonitor){
			ss >> thirdMessageValue;
		printf("%i ", thirdMessageValue);
		} else {
			ss >> messageString;
			cout<<messageString;
		}
		printf("\n");
		ss.flush();*/
	
		// ---------- Process
		//Switch statement directing to the processing code for the appropriate system call.
		int hasLock = 0;
		int hasCV = 0;
		int hasMV = 0;
		
		printf("Call number: %d \n", callType);
		switch(callType){
			case SC_CreateLock:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				if(numServers == 1){
					ServerCreateLock(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else {
					hasLock = DoIHaveLock(messageString);
					
					if(hasLock == 1){
						printf("i has lock!\n");
						//send yes reply
						int lockIndex = -1;
						
						serverLockLock->Acquire();
						for(int i = 0; i < MAX_LOCKS; i++){
							if(lockArray[i].name == messageString){
								lockIndex = i;
								break;
							}
						}
						serverLockLock->Release();
						
						stringstream ssR (stringstream::in | stringstream::out);
						ssR << lockIndex;
						ssR >> replyMsg;
						ssR.flush();
						
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = currentThread->getMachineId();
						outMailHdr.to = inMailHdr.from;
						outMailHdr.length = strlen(replyMsg) + 1;
						shouldSendMessage = 1;
						
					} else { //hasLock = 0
						printf("no has lock :(\n");
						//send DYH messages to other servers
						shouldSendMessage = 0;
						
						updatePendingRequestTable(DYH_LOCK, SC_CreateLock, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
						
						DoYouHaveLock(messageString, SC_CreateLock);
					}
				}
				
				//ServerCreateLock(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				break;
			
			case SC_DestroyLock:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasLock = DoIHaveLock(messageString);
				
				if(hasLock == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_DestroyLock, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(messageString, SC_DestroyLock);
				} else { //hasLock = 1
					ServerDestroyLock(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}
				break;
				
			case SC_AcquireLock:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasLock = DoIHaveLock(messageString);
				
				if(hasLock == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_AcquireLock, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(messageString, SC_AcquireLock);
				} else { //hasLock = 1
					ServerAcquireLock(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}
				
				break;
			
			case SC_ReleaseLock:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				int needReply;
				ss >> needReply;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasLock = DoIHaveLock(messageString);
				
				if(hasLock == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_ReleaseLock, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(messageString, SC_ReleaseLock);
				} else { //hasLock = 1
					ServerReleaseLock(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage, needReply);
				}
				
				break;
			
			case SC_Condition_Create:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				if(numServers == 1){
					ServerCreateCondition(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else {				
					hasCV = DoIHaveCV(messageString);
					
					if(hasCV == 1){
						int cvIndex = -1;
						
						serverCVLock->Acquire();
						for(int i = 0; i < MAX_CONDS; i++){
							if(condArray[i].name == messageString){
								cvIndex = i;
								break;
							}
						}
						serverCVLock->Release();
						
						stringstream ssR (stringstream::in | stringstream::out);
						ssR << cvIndex;
						ssR >> replyMsg;
						ssR.flush();
						
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = currentThread->getMachineId();
						outMailHdr.to = inMailHdr.from;
						outMailHdr.length = strlen(replyMsg) + 1;
						shouldSendMessage = 1;
						
					} else { //hasCV = 0
						//send DYH messages to other servers
						shouldSendMessage = 0;
						
						updatePendingRequestTable(DYH_CV, SC_Condition_Create, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
						
						DoYouHaveCV(messageString, SC_Condition_Create);
					}
				}
				//ServerCreateCondition(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				break;
						
			case SC_Condition_Destroy:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasCV = DoIHaveCV(messageString);
				
				if(hasCV == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_CV, SC_Condition_Destroy, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveCV(messageString, SC_Condition_Destroy);
				} else { //hasCV = 1
					ServerDestroyCondition(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}
				break;
			
			case SC_Condition_Wait:
				printf("%i ", callType);
				ss >> read1; //lock name
				cout << read1;
				printf(" ");
				ss >> read2; //cv name
				cout << read2;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasCV = DoIHaveCV(read2);
				hasLock = DoIHaveLock(read1);
				
				if(hasCV == 1 && hasLock == 1){ //server has both
					//printf("i have both!\n");
					ServerWaitCondition(replyMsg, read1, read2, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else if(hasCV == 1 && hasLock == 0){ //has CV, no lock
					//printf("I don't have the lock\n");
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_Condition_Wait, read1, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(read1, SC_Condition_Wait);
				} else { //no cv, need to forward the message!
					//printf("i don't have the cv, need to forward the message '%s'\n", clientMessage);
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_CV, SC_Condition_Wait, read2, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveCV(read2, SC_Condition_Wait);
				}
				break;
			
			case SC_Condition_Signal:
				printf("%i ", callType);
				ss >> read1; //lock name
				cout << read1;
				printf(" ");
				ss >> read2; //cv name
				cout << read2;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasCV = DoIHaveCV(read2);
				hasLock = DoIHaveLock(read1);
				
				if(hasCV == 1 && hasLock == 1){ //server has both
					ServerSignalCondition(replyMsg, read1, read2, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else if(hasCV == 1 && hasLock == 0){ //has CV, no lock
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_Condition_Signal, read1, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(read1, SC_Condition_Signal);
				} else { //no cv, need to forward the message!
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_CV, SC_Condition_Signal, read2, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveCV(read2, SC_Condition_Signal);	
				}
				break;

			case SC_Condition_Broadcast:
				printf("%i ", callType);
				ss >> read1; //lock name
				cout << read1;
				printf(" ");
				ss >> read2; //cv name
				cout << read2;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasCV = DoIHaveCV(read2);
				hasLock = DoIHaveLock(read1);
				
				if(hasCV == 1 && hasLock == 1){ //server has both
					ServerBroadcastCondition(replyMsg, read1, read2, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else if(hasCV == 1 && hasLock == 0){ //has CV, no lock
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_LOCK, SC_Condition_Broadcast, read1, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveLock(read1, SC_Condition_Broadcast);
				} else { //no cv, need to forward the message!
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_CV, SC_Condition_Broadcast, read2, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveCV(read2, SC_Condition_Broadcast);	
				}
				break;
	
			case SC_CreateMonitor:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				if(numServers == 1){
					CreateMonitor_Syscall(replyMsg, messageString, 0, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				} else {
					hasMV = DoIHaveMV(messageString);
					
					if(hasMV == 1){
						//send yes reply
						int mvIndex = -1;
						
						serverMVLock->Acquire();
						for(int i = 0; i < MAX_MONITORS; i++){
							if(serverMonitorVariables[i].name == messageString){
								mvIndex = i;
								break;
							}
						}
						serverMVLock->Release();
						
						stringstream ssR (stringstream::in | stringstream::out);
						ssR << mvIndex;
						ssR >> replyMsg;
						ssR.flush();
						
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = currentThread->getMachineId();
						outMailHdr.to = inMailHdr.from;
						outMailHdr.length = strlen(replyMsg) + 1;
						shouldSendMessage = 1;
						
					} else { //hasMV = 0
						//send DYH messages to other servers
						shouldSendMessage = 0;
						
						updatePendingRequestTable(DYH_MV, SC_CreateMonitor, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
						
						DoYouHaveMV(messageString, SC_CreateMonitor);
					}
				}
				//CreateMonitor_Syscall(replyMsg, messageString, 0, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				break;
				
			case SC_DestroyMonitor:
				printf("%i ", callType);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasMV = DoIHaveMV(messageString);
				
				if(hasMV == 0){
					shouldSendMessage = 0; 
					
					updatePendingRequestTable(DYH_MV, SC_DestroyMonitor, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveMV(messageString, SC_DestroyMonitor);
				} else { //hasMV = 1
					DestroyMonitor_Syscall(replyMsg, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}				
				break;
				
			case SC_GetMonitor:
				printf("%i ", callType);
				ss >> firstMessageValue;
				printf("%i ", firstMessageValue);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasMV = DoIHaveMV(messageString);
				
				if(hasMV == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_MV, SC_GetMonitor, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveMV(messageString, SC_GetMonitor);
				} else { //hasMV = 1
					GetMonitor_Syscall(replyMsg, firstMessageValue, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}
				break;
				
			case SC_SetMonitor:
				printf("%i ", callType);
				ss >> firstMessageValue;
				printf("%i ", firstMessageValue);
				ss >> secondMessageValue;
				printf("%i ", secondMessageValue);
				ss >> messageString;
				cout<<messageString;
				
				printf("\n");
				ss.flush();
				printf("Sender: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
				
				hasMV = DoIHaveMV(messageString);
				
				if(hasMV == 0){
					shouldSendMessage = 0;
					
					updatePendingRequestTable(DYH_MV, SC_SetMonitor, messageString, clientMessage, inPktHdr.from, inMailHdr.from);
					
					DoYouHaveMV(messageString, SC_SetMonitor);
				} else { //hasMV = 1
					SetMonitor_Syscall(replyMsg, firstMessageValue, secondMessageValue, messageString, inPktHdr, inMailHdr, outPktHdr, outMailHdr, shouldSendMessage);
				}
				break;
	
			default:
				printf("BAD SYSCALL!  Exiting nachos. \n");
				interrupt->Halt();
				break;
		}
		
		// ---------- Send Reply (if necessary)
		// -- Message Portion -- //
		if(shouldSendMessage == 1){
			outMailHdr.length = strlen(replyMsg) + 1;
			bool success = postOffice->Send(outPktHdr, outMailHdr, replyMsg);
			if ( !success ) {
				printf("The postOffice Send failed. Terminating Nachos.\n");
				interrupt->Halt();
			} else {
				printf("Server sent reply '%s' to machine %i, mailbox %i!\n", replyMsg, outPktHdr.to, outMailHdr.to);
			}
			shouldSendMessage = 0;
		}

		printf("\n\n");
		
	}
}

void HandleServerThread(int numServers){
	ASSERT(numServers > 0);
	ASSERT(numServers <= 5);
	numberOfServers = numServers;
	printf("\tserver-server thread\n");
	
	PacketHeader outPktHdr, inPktHdr;
	MailHeader outMailHdr, inMailHdr;
	
	int msgType;
	int entityType;
	int call;
	int response;
	string name;
	char buffer[maxMailSize];
	int dyhTime;
	
	while(true){
		printf("\n\n");
		time_t curTime;
		//curTime = time (NULL);
		//printf("\tcurTime = %i\n", curTime);
		postOffice->Receive(server_mailbox, &inPktHdr, &inMailHdr, buffer);
		
		//char* serverMessage = buffer;
		
		stringstream ss (stringstream::in | stringstream::out);
		msgType = 0;
		entityType = 0;
		call = 0;
		response = 0;
		name.clear();
		ss.str("");
		
		ss << buffer;
		ss >> msgType;
		
		if(msgType == DYH_REPLY){ //a reply
			printf("\tjust got a dyh reply from machine %i: ", inPktHdr.from);
			printf(buffer);
			printf("\n");
			ss >> entityType;
			ss >> call;
			ss >> response;
			ss >> name;
			
			
			printf("\t");
			int foundRequest = DoIHaveRequest(entityType, call, name);
			
			printf("\tfound request at %i\n", foundRequest);
			printf("\t[%i].name = %s\n", foundRequest, pendingRequests[foundRequest].name.c_str());
			printf("\t[%i].msg = '%s'\n", foundRequest, pendingRequests[foundRequest].msg.c_str());
			
			if(foundRequest != -1){
				printf("\trequest found!\n");
				if(response == 1){ //response is yes
					printf("\tresponse was a yes!\n");
					if(call == SC_CreateLock || call == SC_Condition_Create || call == SC_CreateMonitor){ //create call
						//send reply to client
						printf("\tcreate request!\n");
						int answer = 1337;
						char reply[maxMailSize];
						sprintf(reply, "%i", answer);
						
						pendingRequestLock->Acquire();
						
						outPktHdr.to = pendingRequests[foundRequest].clientMachineID;
						outPktHdr.from = currentThread->getMachineId();
						outMailHdr.to = pendingRequests[foundRequest].clientMailbox;
						outMailHdr.from = client_mailbox;
						outMailHdr.length = strlen(reply) + 1;
						
						pendingRequestLock->Release();
						
						printf("\tabout to send response to client %i: ", outPktHdr.to);
						printf(reply);
						printf("\n");
						bool success = postOffice->Send(outPktHdr, outMailHdr, reply);
						
						if(!success){
							printf("\tpost office send failed!!\n");
							interrupt->Halt();
						}
						
						//check and respond to pending DYHs to other servers
						pendingRequestLock->Acquire();
						
						while(!pendingRequests[foundRequest].pendingDYH.empty()){ //go through the stuff
							char dyh_reply[maxMailSize];
							sprintf(dyh_reply, "%i %i %i %i %s", DYH_REPLY, pendingRequests[foundRequest].pendingDYH.front().type, pendingRequests[foundRequest].pendingDYH.front().call, 0, pendingRequests[foundRequest].pendingDYH.front().name.c_str());
							
							pendingRequests[foundRequest].pendingDYH.pop();
							
							PacketHeader tempPktHdr;
							MailHeader tempMailHdr;
							
							tempPktHdr.to = pendingRequests[foundRequest].pendingDYH.front().machineID;
							tempPktHdr.from = currentThread->getMachineId();
							tempMailHdr.to = server_mailbox;
							tempMailHdr.from = server_mailbox;
							tempMailHdr.length = strlen(dyh_reply) + 1;
							
							bool tempSuccess = postOffice->Send(tempPktHdr, tempMailHdr, dyh_reply);
							
							if(!tempSuccess){
								printf("\tpost office send failed.\n");
								pendingRequestLock->Release();
								interrupt->Halt();
							}
						}
						
						pendingRequestLock->Release();
					} else if(call == SC_Condition_Wait && entityType == DYH_LOCK){
						//case when you own the CV wait but not the lock and are looking for a reply
						printf("\ti owned the CV for wait and was looking for the lock! found who owns it!\n");			
						pendingRequestLock->Acquire();
						//have to get the name of the cv!
						stringstream split (stringstream::in | stringstream::out);
						
						split << pendingRequests[foundRequest].msg;
						int syscall; //not needed
						split >> syscall;
						string lockName; //not needed
						split >> lockName;
						string cvName;
						split >> cvName; //have the cvName now!
						
						//get the client info for storage later!
						int clientMachineID = pendingRequests[foundRequest].clientMachineID;
						int clientMailbox = pendingRequests[foundRequest].clientMailbox;
						
						serverCVLock->Acquire();
						pendingRequestLock->Release();
						
						//find the cv in the table, and append to the waitQueue!
						int condID = -1;
						for(int i = 0; i < MAX_CONDS; i++){
							if(condArray[i].name == cvName){
								condID = i;
								break;
							}
						}
						
						//since I own cv, condID should be set, but validate here anyway
						if(condID == -1){
							printf("\therp derp i actually don't have the cv!\n");
							serverCVLock->Release();
							interrupt->Halt();
						}
						
						if(condArray[condID].state == -1){
							printf("\therp derp cv does not exist...\n");
							serverCVLock->Release();
							interrupt->Halt();
						}
						
						//start to forward the info
						PacketHeader tempPktHdr;
						MailHeader tempMailHdr;
						
						//prep the headers
						tempPktHdr.to = clientMachineID;
						tempPktHdr.from = currentThread->getMachineId();
						tempMailHdr.to = clientMailbox;
						tempMailHdr.from = client_mailbox;
						printf("\tPutting into Wait Cond: %d %d \n", clientMachineID, clientMailbox);  //DEBUG
						
						//put the headers in the queue
						condArray[condID].lockUsed = 1; //set it to true? can't get the actual lock index..
						condArray[condID].outgoingMsgPktHdr.push(tempPktHdr);
						condArray[condID].outgoingMsgMailHdr.push(tempMailHdr);
						
						serverCVLock->Release();
						
						//send release to lock owning server
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = clientMachineID;
						outMailHdr.to = client_mailbox;
						outMailHdr.from = clientMailbox;
						
						char msg[maxMailSize];
						//formulating a release lock message, don't send a reply to that thread though!
						int needReply = 0;
						sprintf(msg, "%i %s %i", SC_ReleaseLock, name.c_str(), needReply);
						outMailHdr.length = strlen(msg) + 1;
						
						printf("\tabout to forward release lock msg to machine %i: ", outPktHdr.to);
						printf(msg);
						printf("\n");
						bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
						
						if(!success){
							printf("\tpostOffice send failed.\n");
							interrupt->Halt();
						}
						
						//interrupt->Halt();
					} else if(call == SC_Condition_Signal && entityType == DYH_LOCK){
						//case when you own the CV for signal but not the lock and are looking for a reply
						printf("\ti owned the CV for signal and was looking for the lock! found who owns it!\n");
						
						pendingRequestLock->Acquire();				
						//have to get the name of the cv!
						stringstream split (stringstream::in | stringstream::out);
						
						split << pendingRequests[foundRequest].msg;
						int syscall; //not needed
						split >> syscall;
						string lockName; //not needed
						split >> lockName;
						string cvName;
						split >> cvName; //have the cvName now!
						
						serverCVLock->Acquire();
						pendingRequestLock->Release();
						
						//find the cv!
						int condID = -1;
						for(int i = 0; i < MAX_CONDS; i++){
							if(condArray[i].name == cvName){
								condID = i;
								break;
							}
						}		
						
						//since I own cv, condID should be set, but validate here anyway
						if(condID == -1){
							printf("\therp derp i actually don't have the cv!\n");
							interrupt->Halt();
						}
						
						if(condArray[condID].state == -1){
							printf("\therp derp cv does not exist...\n");
							interrupt->Halt();
						}
						
						if(!condArray[condID].outgoingMsgPktHdr.empty() && !condArray[condID].outgoingMsgMailHdr.empty()){
							//get the correct info to forward message
							int clientMachineID = condArray[condID].outgoingMsgPktHdr.front().to; //misnomer, machineID of the waiting thread
							int clientMailbox = condArray[condID].outgoingMsgMailHdr.front().to; //misnomer, mailbox of the waiting thread
							
							//remove the waiting thing
							condArray[condID].outgoingMsgPktHdr.pop();
							condArray[condID].outgoingMsgMailHdr.pop();
							
							//send acquire to lock owning server from the woken up thread!
							outPktHdr.to = inPktHdr.from;
							outPktHdr.from = clientMachineID;
							outMailHdr.to = client_mailbox;
							outMailHdr.from = clientMailbox;
							
							char msg[maxMailSize];
							sprintf(msg, "%i %s", SC_AcquireLock, name.c_str());
							outMailHdr.length = strlen(msg) + 1;
							
							printf("\tabout to forward acquire lock msg to machine %i: ", outPktHdr.to);
							printf(msg);
							printf("\n");
							bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
							
							if(!success){
								printf("\tpostOffice send failed.\n");
								interrupt->Halt();
							}
							
							//respond to client
							PacketHeader tempPktHdr;
							MailHeader tempMailHdr;
							
							pendingRequestLock->Acquire();
							
							int requestingMachineID = pendingRequests[foundRequest].clientMachineID; //machine that requested the signal
							int requestingMailbox = pendingRequests[foundRequest].clientMailbox; //mailbox that requested the signal
							
							pendingRequestLock->Release();
							
							tempPktHdr.to = requestingMachineID;
							tempPktHdr.from = currentThread->getMachineId();
							tempMailHdr.to = requestingMailbox;
							tempMailHdr.from = client_mailbox;
							
							char replyMsg[maxMailSize];
							sprintf(replyMsg, "%i", 0);
							tempMailHdr.length = strlen(replyMsg) + 1;
							
							printf("\tabout to reply to machine %i: ", outPktHdr.to);
							printf(replyMsg);
							printf("\n");
							bool replySuccess = postOffice->Send(tempPktHdr, tempMailHdr, replyMsg);
							
							if(!replySuccess){
								printf("\tpostOffice send failed.\n");
								serverCVLock->Release();
								interrupt->Halt();
							}

						} else {
							printf("\tnothing in %s's waitQueue!\n", cvName.c_str());
							condArray[condID].lockUsed = -1;
							
							pendingRequestLock->Acquire();
							
							int clientMachineID = pendingRequests[foundRequest].clientMachineID; //machine that requested signal
							int clientMailbox = pendingRequests[foundRequest].clientMailbox; //client's mailbox
							
							pendingRequestLock->Release();
							
							outPktHdr.to = clientMachineID;
							outPktHdr.from = currentThread->getMachineId();
							outMailHdr.to = clientMailbox;
							outMailHdr.from = client_mailbox;
							
							char msg[maxMailSize];
							sprintf(msg, "%i", 0);
							outMailHdr.length = strlen(msg) + 1;
							
							printf("\tabout to reply to machine %i: ", outPktHdr.to);
							printf(msg);
							printf("\n");
							bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
							
							if(!success){
								printf("\tpostOffice send failed.\n");
								serverCVLock->Release();
								interrupt->Halt();
							}
						} 
						serverCVLock->Release();
						//interrupt->Halt();
					} else if(call == SC_Condition_Broadcast && entityType == DYH_LOCK){
						//case when you own the CV for broadcast but not the lock and are looking for a reply
						printf("\ti owned the CV for broadcast and was looking for the lock! found who owns it!\n");
						
						pendingRequestLock->Acquire();				
						//have to get the name of the cv!
						stringstream split (stringstream::in | stringstream::out);
						
						split << pendingRequests[foundRequest].msg;
						int syscall; //not needed
						split >> syscall;
						string lockName; //not needed
						split >> lockName;
						string cvName;
						split >> cvName; //have the cvName now!
						
						serverCVLock->Acquire();
						pendingRequestLock->Release();
						
						//find the cv!
						int condID = -1;
						for(int i = 0; i < MAX_CONDS; i++){
							if(condArray[i].name == cvName){
								condID = i;
								break;
							}
						}		
						
						//since I own cv, condID should be set, but validate here anyway
						if(condID == -1){
							printf("\therp derp i actually don't have the cv!\n");
							interrupt->Halt();
						}
						
						if(condArray[condID].state == -1){
							printf("\therp derp cv does not exist...\n");
							interrupt->Halt();
						}
						
						if(!condArray[condID].outgoingMsgPktHdr.empty() && !condArray[condID].outgoingMsgMailHdr.empty()){
							while(!condArray[condID].outgoingMsgPktHdr.empty() && !condArray[condID].outgoingMsgMailHdr.empty()){
								//get the correct info to forward message
								int clientMachineID = condArray[condID].outgoingMsgPktHdr.front().to; //misnomer, machineID of the waiting thread
								int clientMailbox = condArray[condID].outgoingMsgMailHdr.front().to; //misnomer, mailbox of the waiting thread
								
								//remove the waiting thing
								condArray[condID].outgoingMsgPktHdr.pop();
								condArray[condID].outgoingMsgMailHdr.pop();
								
								//send acquire to lock owning server from the woken up thread!
								outPktHdr.to = inPktHdr.from;
								outPktHdr.from = clientMachineID;
								outMailHdr.to = client_mailbox;
								outMailHdr.from = clientMailbox;
								
								char msg[maxMailSize];
								sprintf(msg, "%i %s", SC_AcquireLock, name.c_str());
								outMailHdr.length = strlen(msg) + 1;
								
								printf("\tabout to forward acquire lock msg to machine %i: ", outPktHdr.to);
								printf(msg);
								printf("\n");
								bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
								
								if(!success){
									printf("\tpostOffice send failed.\n");
									serverCVLock->Release();
									interrupt->Halt();
								}								
							}
							//respond to client
							PacketHeader tempPktHdr;
							MailHeader tempMailHdr;
							
							pendingRequestLock->Acquire();
							
							int requestingMachineID = pendingRequests[foundRequest].clientMachineID; //machine that requested the signal
							int requestingMailbox = pendingRequests[foundRequest].clientMailbox; //mailbox that requested the signal
							
							pendingRequestLock->Release();
							
							tempPktHdr.to = requestingMachineID;
							tempPktHdr.from = currentThread->getMachineId();
							tempMailHdr.to = requestingMailbox;
							tempMailHdr.from = client_mailbox;
							
							char replyMsg[maxMailSize];
							sprintf(replyMsg, "%i", 0);
							tempMailHdr.length = strlen(replyMsg) + 1;
							
							printf("\tabout to reply to machine %i: ", outPktHdr.to);
							printf(replyMsg);
							printf("\n");
							bool replySuccess = postOffice->Send(tempPktHdr, tempMailHdr, replyMsg);
							
							if(!replySuccess){
								printf("\tpostOffice send failed.\n");
								serverCVLock->Release();
								interrupt->Halt();
							}
						} else {
							printf("\tnothing in %s's waitQueue!\n", cvName.c_str());
							condArray[condID].lockUsed = -1;
							
							pendingRequestLock->Acquire();
							
							int clientMachineID = pendingRequests[foundRequest].clientMachineID; //machine that requested signal
							int clientMailbox = pendingRequests[foundRequest].clientMailbox; //client's mailbox
							
							pendingRequestLock->Release();
							
							outPktHdr.to = clientMachineID;
							outPktHdr.from = currentThread->getMachineId();
							outMailHdr.to = clientMailbox;
							outMailHdr.from = client_mailbox;
							
							char msg[maxMailSize];
							sprintf(msg, "%i", 0);
							outMailHdr.length = strlen(msg) + 1;
							
							printf("\tabout to reply to machine %i: ", outPktHdr.to);
							printf(msg);
							printf("\n");
							bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
							
							if(!success){
								printf("\tpostOffice send failed.\n");
								serverCVLock->Release();
								interrupt->Halt();
							}
						}
						
						serverCVLock->Release();
						//interrupt->Halt();
					} else { //not a create call
						//forward message to server
						printf("\tnot a create request!\n");
						pendingRequestLock->Acquire();
						
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = pendingRequests[foundRequest].clientMachineID;
						outMailHdr.to = client_mailbox;
						outMailHdr.from = pendingRequests[foundRequest].clientMailbox;
						
						char msg[maxMailSize];
						sprintf(msg, "%s", pendingRequests[foundRequest].msg.c_str());
						outMailHdr.length = strlen(msg) + 1;
						
						pendingRequestLock->Release();
						
						printf("\tabout to forward msg to machine %i: ", outPktHdr.to);
						printf(msg);
						printf("\n");
						bool success = postOffice->Send(outPktHdr, outMailHdr, msg);
						
						if(!success){
							printf("\tpostOffice send failed.\n");
							interrupt->Halt();
						}
					}
					
					//clear pending request entry
					printf("\t");
					clearPendingRequestEntry(foundRequest);
				} else { //response is no
					printf("\tresponse was a no!\n");
					pendingRequestLock->Acquire();
					pendingRequests[foundRequest].numberOfNoReplies++;
					int numNoReplies = pendingRequests[foundRequest].numberOfNoReplies;
					int clientMachineID = pendingRequests[foundRequest].clientMachineID;
					int clientMailbox = pendingRequests[foundRequest].clientMailbox;
					//string name = pendingRequests[foundRequest].name;
					pendingRequestLock->Release();
					
					//printf("numNoReplies %i; numberOfServers %i\n", numNoReplies, numberOfServers);
					if(numNoReplies == numberOfServers - 1){
						//entity does not exist..
						//printf("got all no's!\n");
						if(call == SC_CreateLock || call == SC_Condition_Create || call == SC_CreateMonitor){ //create call
							//create it and send reply to client!
							char reply[maxMailSize];
							int ssm = 0;
							//printf("\tdeciding what to do...\n");
							
							PacketHeader clientPktHdr;
							MailHeader clientMailHdr;
							
							clientPktHdr.from = clientMachineID;
							clientMailHdr.from = clientMailbox;
							//printf("\tclientPktHdr.from = %i; clientMailHdr.from = %i\n", clientPktHdr.from, clientMailHdr.from);
							printf("\t");
							switch(call){
								case SC_CreateLock:
									ServerCreateLock(reply, name, clientPktHdr, clientMailHdr, outPktHdr, outMailHdr, ssm);
									break;
								case SC_Condition_Create:
									ServerCreateCondition(reply, name, clientPktHdr, clientMailHdr, outPktHdr, outMailHdr, ssm);
									break;
								case SC_CreateMonitor:
									CreateMonitor_Syscall(reply, name, 0, clientPktHdr, clientMailHdr, outPktHdr, outMailHdr, ssm);
									break;
								default:
									printf("\tnot a create call\n");
									interrupt->Halt();
									break;
							}
							
							//reply to the client!
							printf("\tabout to send dyh reply to machine %i: ", outPktHdr.to);
							printf(reply);
							printf("\n");
							
							printf("\t");
							clearPendingRequestEntry(foundRequest);
							
							bool success = postOffice->Send(outPktHdr, outMailHdr, reply);
							
							if(!success){
								printf("\tpost office send failed!!!!\n");
								interrupt->Halt();
							}
							
						} else { //not a create call
							//send error message
							printf("\terror, the entity does not exist!\n");
							/** TODO */
							interrupt->Halt();
						} 
					} else { //not all no's yet
						//do nothing
						printf("\tneed some more no's or a yes...\n");
					} 
					
				}
			} else { //foundRequest = -1
				//do nothing, already processed. return an "already processed message"				
				/** TODO?? */
			}
			
		} else if(msgType == DYH_MSG){ //a message
			printf("\tjust got a dyh message from machine %i: ", inPktHdr.from);
			printf(buffer);
			printf("\n");
			ss >> entityType;
			ss >> call;
			ss >> name;
			ss >> dyhTime;
			//printf("\tdyhTime = %i\n", dyhTime);
			
			int foundEntity = 0;
			printf("\t");
			switch(entityType){
				case DYH_LOCK:
					foundEntity = DoIHaveLock(name);
					break;
				case DYH_CV:
					foundEntity = DoIHaveCV(name);
					break;
				case DYH_MV:
					foundEntity = DoIHaveMV(name);
					break;
				default:
					printf("bad entity type. exiting\n");
					interrupt->Halt();
					break;
			}
			
			if(foundEntity == 1){ //found entity
				printf("\tentity found!\n");
				char dyh_reply[maxMailSize];
				sprintf(dyh_reply, "%i %i %i %i %s", DYH_REPLY, entityType, call, 1, name.c_str()); //send yes reply
				
				outPktHdr.to = inPktHdr.from;
				outPktHdr.from = currentThread->getMachineId();
				outMailHdr.to = server_mailbox;
				outMailHdr.from = server_mailbox;
				outMailHdr.length = strlen(dyh_reply) + 1;
				
				printf("\tabout to send reply to machine %i: ", outPktHdr.to);
				printf(dyh_reply);
				printf("\n");
				bool success = postOffice->Send(outPktHdr, outMailHdr, dyh_reply);
				
				if(!success){
					printf("post office send failed!!!\n");
					interrupt->Halt();
				}
				
			} else { //entity not found
				printf("\tno entity found!\n");
				if(call == SC_CreateLock || call == SC_Condition_Create || call == SC_CreateMonitor){ //create call
					//search pending request table
					printf("\tit was a create call!\n");
					printf("\t");
					int foundRequest = DoIHaveRequest(entityType, call, name);
					
					if(foundRequest != -1){ //pending request found, special case 1
						printf("\tSPECIAL CASE ONE ENCOUNTERED, TIME TO HANDLE AFTER NORMAL CASE TESTED!\n");
						
						pendingRequestLock->Acquire();
						if(dyhTime > pendingRequests[foundRequest].timestamp){ //my timestamp is earlier
							//don't send reply, queue up dyh message
							//DYH dyh = new DYH(inPktHdr.from, server_mailbox, response);
							DYH dyh;
							dyh.machineID = inPktHdr.from;
							dyh.mailbox = server_mailbox;
							dyh.type = entityType;
							dyh.call = call;
							dyh.name = name;
							//dyh.response = response;
							
							pendingRequests[foundRequest].pendingDYH.push(dyh);
						} else if(dyhTime < pendingRequests[foundRequest].timestamp){ //my timestamp is later
							//send a no
							outPktHdr.to = inPktHdr.from;
							outPktHdr.from = currentThread->getMachineId();
							outMailHdr.to = server_mailbox;
							outMailHdr.from = server_mailbox;
							
							char dyh_reply[maxMailSize];
							sprintf(dyh_reply, "%i %i %i %i %s", DYH_REPLY, entityType, call, 0, name.c_str()); //a no reply
							outMailHdr.length = strlen(dyh_reply) + 1;
							
							bool success = postOffice->Send(outPktHdr, outMailHdr, dyh_reply);
							
							if(!success){
								printf("\tpost office send failed!!!!!!\n");
								pendingRequestLock->Release();
								interrupt->Halt();
							} 
						} else { //equal...if my machineID is less, I have priority??
							printf("\tyesterday...all my troubles seemed so far away...\n");
							pendingRequestLock->Release();
							interrupt->Halt();
						}
						pendingRequestLock->Release();
					} else { //pending request not found
						char dyh_reply[maxMailSize];
						sprintf(dyh_reply, "%i %i %i %i %s", DYH_REPLY, entityType, call, 0, name.c_str()); //send no reply
						
						outPktHdr.to = inPktHdr.from;
						outPktHdr.from = currentThread->getMachineId();
						outMailHdr.to = server_mailbox;
						outMailHdr.from = server_mailbox;
						outMailHdr.length = strlen(dyh_reply) + 1;
						
						printf("\tabout to send reply to machine %i: ", outPktHdr.to);
						printf(dyh_reply);
						printf("\n");
						bool success = postOffice->Send(outPktHdr, outMailHdr, dyh_reply);
				
						if(!success){
							printf("\tpost office send failed!!!\n");
							interrupt->Halt();
						}
					}
				} else { //not create request
					printf("\tit wasn't a create call!\n");
					char dyh_reply[maxMailSize];
					sprintf(dyh_reply, "%i %i %i %i %s", DYH_REPLY, entityType, call, 0, name.c_str()); //send no reply
					
					outPktHdr.to = inPktHdr.from;
					outPktHdr.from = currentThread->getMachineId();
					outMailHdr.to = server_mailbox;
					outMailHdr.from = server_mailbox;
					outMailHdr.length = strlen(dyh_reply) + 1;
					
					printf("\tabout to send reply to machine %i: ", outPktHdr.to);
					printf(dyh_reply);
					printf("\n");
					bool success = postOffice->Send(outPktHdr, outMailHdr, dyh_reply);
				
					if(!success){
						printf("\tpost office send failed!!!\n");
						interrupt->Halt();
					}
				}
			}
		} else { //not an appropriate type, die
			printf("\tin appropriate server-server message type %i!\n", msgType);
			interrupt->Halt();
		} 
	}

}

void MailTest(int farAddr){
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
    char *data = "Hello there!";
    char *ack = "Got it!";
    char buffer[MaxMailSize];

	if(farAddr != 0){
		printf("machineID 0 is reserved for Server!\n");
		return;
	} else {
		printf("use -x to launch the tests!\n");
		//printf("launching ../test/testP3d!\n");
		return;
		//runTests();
	}
	
	/*
    // construct packet, mail header for original message
    // To: destination machine, mailbox 0
    // From: our machine, reply to: mailbox 1
    outPktHdr.to = farAddr;		
    outMailHdr.to = 0;
    outMailHdr.from = 1;
    outMailHdr.length = strlen(data) + 1;

    // Send the first message
    bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the first message from the other machine
    postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Send acknowledgement to the other machine (using "reply to" mailbox
    // in the message that just arrived
    outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(ack) + 1;
    success = postOffice->Send(outPktHdr, outMailHdr, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the ack from the other machine to the first message we sent.
    postOffice->Receive(1, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);


    // Then we're done!
    interrupt->Halt();
	*/
}

void ServerCreateLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){

	//CREATE LOCK
	printf("Server: CreateLock requested.\n");
	serverLockLock->Acquire();
	int newLockID = -1;
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == messageString){  //lock with requested name already exists
			newLockID = i;
			if(lockArray[newLockID].state == -1){
				lockArray[newLockID].state = 0;
			}
			break;
		}
	}
	if(newLockID == -1){  //new lock must be created
		newLockID = nextLockIndex;
		lockArray[newLockID].state = 0;
		lockArray[newLockID].name = messageString;
		lockArray[newLockID].ownerMachineID = -1;
		lockArray[newLockID].ownerMailboxNum = -1;
		nextLockIndex++;
	}
	//Prep reply message
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << newLockID;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.from = client_mailbox;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	
	serverLockLock->Release();
	// END OF CREATELOCK
	return;
}

void ServerAcquireLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: AcquireLock requested.\n");
	serverLockLock->Acquire();
	int lockID = -1;
		
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == messageString){
			lockID = i;
			break;
		}
	}
	
	if(lockID == -1){
		printf("error in acquiring lock, no lock of that name!\n");
		serverLockLock->Release();
		interrupt->Halt();
	}
	
	//Validate
	if(lockArray[lockID].state == -1){
		printf("Error acquiring lock that does not exist. \n");
	}
	if(lockArray[lockID].ownerMachineID == inPktHdr.from && lockArray[lockID].ownerMailboxNum == inMailHdr.from){
		printf("Error acquiring same lock twice. \n");
		//Allow system to continue running
		outPktHdr.to = inPktHdr.from;
		outPktHdr.from = currentThread->getMachineId();
		outMailHdr.to = inMailHdr.from;
		outMailHdr.from = client_mailbox;
		
		stringstream ssR (stringstream::in | stringstream::out);
		ssR << lockID;
		ssR >> reply;
		ssR.flush();
		
		shouldSendMessage = 1;
		serverLockLock->Release();
		return;
	}
	
	//Check if ServerLock is busy
	if(lockArray[lockID].state == 0){	//if not
		//set ServerLock to busy
		lockArray[lockID].state = 1;
		//set ServerLock owner
		lockArray[lockID].ownerMachineID = inPktHdr.from;
		lockArray[lockID].ownerMailboxNum = inMailHdr.from;
		// ----- Send message to acknowledge lock is acquired
		outPktHdr.to = inPktHdr.from;
		outPktHdr.from = currentThread->getMachineId();
		outMailHdr.to = inMailHdr.from;
		outMailHdr.from = client_mailbox;
		
		stringstream ssR (stringstream::in | stringstream::out);
		ssR << lockID;
		ssR >> reply;
		ssR.flush();
		shouldSendMessage = 1;
	} else { //else, lock is busy, and we will go in queue
		//prep headers
		printf("lock %s is busy!\n", messageString.c_str());
		PacketHeader tempPktHdr;
		MailHeader tempMailHdr;
		tempPktHdr.to = inPktHdr.from;
		tempPktHdr.from = currentThread->getMachineId();
		tempMailHdr.to = inMailHdr.from;
		tempMailHdr.from = serverThread1BoxNum;
		// put headers in the queue
		lockArray[lockID].outgoingMsgPktHdr.push(tempPktHdr);
		lockArray[lockID].outgoingMsgMailHdr.push(tempMailHdr);
	}
	serverLockLock->Release();
	return;
}

void ServerReleaseLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage, int &needReply){
	printf("Server: ReleaseLock requested.\n");
	serverLockLock->Acquire();
	int lockID = -1;
		
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == messageString){
			lockID = i;
			break;
		}
	}
	
	if(lockID == -1){
		printf("error in releasing lock, no lock of that name!\n");
		serverLockLock->Release();
		interrupt->Halt();
	}
	
	//Validate
	int errorMessage = -1;
	if(lockArray[lockID].state == -1){
		printf("Error releasing lock that does not exist. \n");
	}
	else if(lockArray[lockID].ownerMachineID != inPktHdr.from || lockArray[lockID].ownerMailboxNum != inMailHdr.from){ //in synch, we don't die, so don't die here?
		printf("Warning, you don't own this lock! Release not done!\n");
		//printf("Error releasing lock that the thread doesn't own!  Halting nachos! \n");
		//serverLockLock->Release();
		//interrupt->Halt();
	}
	else if(lockArray[lockID].state == 0){
		printf("Error releasing lock that is not busy! \n");
	}
	//Check if ServerLock is busy
	else if(lockArray[lockID].state == 1){	//if so
		errorMessage = 0;
		if(lockArray[lockID].outgoingMsgPktHdr.empty()){
			lockArray[lockID].state = 0;
			lockArray[lockID].ownerMailboxNum = -1;
		} else { //else someone is waiting to acquire the lock, let them acquire it here
			//printf("Going to prepare to send wakeup msg. \n"); //DEBUG
			//preparing headers to wake up waiting thread
			PacketHeader tempPktHdr;
			MailHeader tempMailHdr;
			tempPktHdr.to = lockArray[lockID].outgoingMsgPktHdr.front().to;
			tempPktHdr.from = lockArray[lockID].outgoingMsgPktHdr.front().from;
			tempMailHdr.to = lockArray[lockID].outgoingMsgMailHdr.front().to;
			//giving next owner the lock
				
			//set ServerLock to busy
			lockArray[lockID].state = 1;
			//set ServerLock owner
			lockArray[lockID].ownerMachineID = lockArray[lockID].outgoingMsgPktHdr.front().to;
			lockArray[lockID].ownerMailboxNum = lockArray[lockID].outgoingMsgMailHdr.front().to;
			
			//removing next owner from wait queue
			lockArray[lockID].outgoingMsgPktHdr.pop();
			lockArray[lockID].outgoingMsgMailHdr.pop();
			tempMailHdr.from = serverThread1BoxNum;
			
			//Send wakeup message
			//printf("About to load wakeup msg.\n"); //DEBUG
			char wakeup[maxMailSize];
			stringstream ssW (stringstream::in | stringstream::out);
			ssW << lockID;
			ssW >> wakeup;
			tempMailHdr.length = strlen(wakeup) + 1;
			bool success = postOffice->Send(tempPktHdr, tempMailHdr, wakeup);
			if ( !success ) {
				printf("The postOffice Send failed. Terminating Nachos.\n");
				serverLockLock->Release();
				interrupt->Halt();
			} else {
				printf("Server sent wakeup message to machine %i mailbox %i! '%s'\n", tempPktHdr.to, tempMailHdr.to, wakeup);
			}
		}
	}
		// ----- Send message to acknowledge lock is released
		//printf("About to load normal return message.\n");  //DEBUG
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();	
	outMailHdr.to = inMailHdr.from;
	outMailHdr.from = serverThread1BoxNum;
	
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorMessage;
	ssR >> reply;
	ssR.flush();
	
	if(needReply==1){
		shouldSendMessage = 1;
	} else {
		shouldSendMessage = 0;
	}
	serverLockLock->Release();
	return;
}

void ServerDestroyLock(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: DestroyLock requested.\n");
	serverLockLock->Acquire();
	int lockID = -1;
	
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == messageString){
			lockID = i;
			break;
		}
	}
	
	if(lockID == -1){
		printf("error in deleting lock, no lock of that name!\n");
		serverLockLock->Release();
		interrupt->Halt();
	}
	
	int errorMessage = -1;
	if(lockArray[lockID].state == 1){  //lock is busy
		printf("Error, lock deleted while it was still busy! \n");
	}
	else if(lockArray[lockID].state == -1){  //lock not created
		printf("Error deleting lock that does not exist. \n");
	}
	else{  //normal lock deletion
		lockArray[lockID].state = -1;
		errorMessage = 0;
	}
	//return message to notify no errors
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorMessage;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	
	serverLockLock->Release();
	return;
}

void ServerCreateCondition(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	//CREATECONDITION
	printf("Server: CreateCondition requested.\n");
	serverCVLock->Acquire();
	int newCondID = -1;
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == messageString){  //lock with requested name already exists
			newCondID = i;
			if(condArray[newCondID].state == -1){
				condArray[newCondID].state = 1;
			}
			break;
		}
	}
	
	if(newCondID == -1){  //new lock must be created
		newCondID = nextCondIndex;
		condArray[newCondID].state = 1;
		condArray[newCondID].name = messageString;
		condArray[newCondID].ownerMachineID = -1;
		condArray[newCondID].ownerMailboxNum = -1;
		nextCondIndex++;
	}
	
	serverCVLock->Release();
	
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << newCondID;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	// END OF CREATECONDITION
	return;
}
			
void ServerWaitCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: ConditionWait requested.\n");
	serverCVLock->Acquire();
	serverLockLock->Acquire();
	int lockID = -1;
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == lockName){
			lockID = i;
			break;
		}
	}	
	
	if(lockID == -1){
		printf("error in waiting! no lock with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	int condID = -1;
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == cvName){
			condID = i;
			break;
		}
	}
	
	if(condID == -1){
		printf("error in waiting! no cv with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	//Validate
	if(condArray[condID].state == -1){
		printf("Error acquiring CV that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(lockArray[lockID].state == -1){
		printf("Error accessing lock that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(condArray[condID].lockUsed != -1 && condArray[condID].lockUsed != lockID){
		printf("Error, thread waiting on condition that is already being used in connection with another lock! \n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
		return;
	}
	//put needed information in wait queue of condition
	PacketHeader tempPktHdr;
	MailHeader tempMailHdr;
	tempPktHdr.to = inPktHdr.from;		
	tempPktHdr.from = currentThread->getMachineId();
	tempMailHdr.to = inMailHdr.from;
	tempMailHdr.from = serverThread1BoxNum;
	// put headers in the queue
	printf("Putting into Wait Cond: %d %d \n", inPktHdr.from, inMailHdr.from);  //DEBUG
	condArray[condID].lockUsed = lockID;
	condArray[condID].outgoingMsgPktHdr.push(tempPktHdr);
	condArray[condID].outgoingMsgMailHdr.push(tempMailHdr);
	

	//Release the lock!
	int errorMessage = 0;
	if(lockArray[lockID].outgoingMsgPktHdr.empty()){
		lockArray[lockID].state = 0;
		lockArray[lockID].ownerMailboxNum = -1;
	} else { //else someone is waiting
		printf("Going to prepare to send wakeup msg. \n"); //DEBUG
		//preparing headers to wake up waiting thread
		PacketHeader tempPktHdr2;
		MailHeader tempMailHdr2;
		tempPktHdr2.to = lockArray[lockID].outgoingMsgPktHdr.front().to;
		tempPktHdr2.from = lockArray[lockID].outgoingMsgPktHdr.front().from;
		tempMailHdr2.to = lockArray[lockID].outgoingMsgMailHdr.front().to;
		//giving next owner the lock
		
		//set ServerLock to busy
		lockArray[lockID].state = 1;
		//set ServerLock owner
		lockArray[lockID].ownerMachineID = lockArray[lockID].outgoingMsgPktHdr.front().to;
		lockArray[lockID].ownerMailboxNum = lockArray[lockID].outgoingMsgMailHdr.front().to;
		
		//removing next owner from wait queue
		lockArray[lockID].outgoingMsgPktHdr.pop();
		lockArray[lockID].outgoingMsgMailHdr.pop();
		tempMailHdr2.from = serverThread1BoxNum;
		
		//Send wakeup message
		printf("About to load wakeup msg.\n"); //DEBUG
		char wakeup[maxMailSize];
		stringstream ssW (stringstream::in | stringstream::out);
		ssW << lockID;
		ssW >> wakeup;
		tempMailHdr2.length = strlen(wakeup) + 1;
		bool success = postOffice->Send(tempPktHdr2, tempMailHdr2, wakeup);
		if ( !success ) {
			printf("The postOffice Send failed. Terminating Nachos.\n");
			serverLockLock->Release();
			serverCVLock->Release();
			interrupt->Halt();
		} else {
			printf("Server sent wakeup message!\n");
		}
	}
	serverLockLock->Release();
	serverCVLock->Release();
	return;
}

void ServerSignalCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: ConditionSignal requested.\n");
	serverCVLock->Acquire();
	serverLockLock->Acquire();
	int lockID = -1;
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == lockName){
			lockID = i;
			break;
		}
	}	
	
	if(lockID == -1){
		printf("error in signalling! no lock with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	int condID = -1;
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == cvName){
			condID = i;
			break;
		}
	}
	
	if(condID == -1){
		printf("error in signalling! no cv with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	//Validate
	int errorCode = -1;
	if(condArray[condID].state == -1){
		printf("Error accessing CV that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(lockArray[lockID].state == -1){
		printf("Error accessing lock that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(condArray[condID].outgoingMsgPktHdr.empty()){ //empty, but still need to respond, hence no return; also in synch, does not die, so don't die here?
		printf("Warning, condition signalled with nobody in wait queue!\n");
		//serverLockLock->Release();
		//serverCVLock->Release();
		//return;
	} else { //not empty
		errorCode = 0;
		//Finding next person in wait queue
		printf("Going to prepare the wakeup msg to %i, %d \n", condArray[condID].outgoingMsgPktHdr.front().to, condArray[condID].outgoingMsgMailHdr.front().to); //DEBUG
		PacketHeader tempPktHdr;
		MailHeader tempMailHdr;
		tempPktHdr.to = condArray[condID].outgoingMsgPktHdr.front().to;
		tempPktHdr.from = condArray[condID].outgoingMsgPktHdr.front().from;
		tempMailHdr.to = condArray[condID].outgoingMsgMailHdr.front().to;
		// put headers in the queue
		lockArray[lockID].outgoingMsgPktHdr.push(tempPktHdr);
		lockArray[lockID].outgoingMsgMailHdr.push(tempMailHdr);
		//removing next owner from wait queue
		condArray[condID].outgoingMsgPktHdr.pop();
		condArray[condID].outgoingMsgMailHdr.pop();
		tempMailHdr.from = serverThread1BoxNum;
	}
	//Send wakeup message  // this should not happen because awoken thread does not yet have the lock.  The lock's wait queue will msg the thread when the lock has become available.
	/*
		char wakeup[maxMailSize];
		stringstream ssW (stringstream::in | stringstream::out);
		ssW << condArray[condID].lockUsed;
		ssW >> wakeup;
		tempMailHdr.length = strlen(wakeup) + 1;
	//printf("wakeup msg ready: ");  //DEBUG
	//printf("%s \n", wakeup); //DEBUG
		bool success = postOffice->Send(tempPktHdr, tempMailHdr, wakeup);
		if ( !success ) {
			printf("The postOffice Send failed. Terminating Nachos.\n");
			interrupt->Halt();
		} else {
			printf("Server sent wakeup message!\n");
		}
		*/
	//set lockUsed to -1 since nobody is waiting
	if(condArray[condID].outgoingMsgPktHdr.empty()){
		condArray[condID].lockUsed = -1;
	}
	
	//send error code about signal back to sender
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorCode;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	serverLockLock->Release();
	serverCVLock->Release();
	return;

}

void ServerBroadcastCondition(char reply[], string &lockName, string &cvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){

	printf("Server: ConditionBroadcast requested.\n");
	serverCVLock->Acquire();
	serverLockLock->Acquire();
	int lockID = -1;
	for(int i = 0; i < MAX_LOCKS; i++){
		if(lockArray[i].name == lockName){
			lockID = i;
			break;
		}
	}	
	
	if(lockID == -1){
		printf("error in broadcast! no lock with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	int condID = -1;
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == cvName){
			condID = i;
			break;
		}
	}
	
	if(condID == -1){
		printf("error in broadcast! no cv with that name exists!\n");
		serverLockLock->Release();
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	//Validate
	int errorCode = -1;
	if(condArray[condID].state == -1){
		printf("Error accessing CV that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(lockArray[lockID].state == -1){
		printf("Error accessing lock that does not exist. \n");
		serverLockLock->Release();
		serverCVLock->Release();
		return;
	}
	if(condArray[condID].outgoingMsgPktHdr.empty()){
		printf("Warning, condition signalled with nobody in wait queue!\n");
		//serverLockLock->Release();
		//serverCVLock->Release();
		//return;
	}
	errorCode = 0;
	while(!condArray[condID].outgoingMsgPktHdr.empty()){ //Waking up all threads in wait queue
		printf("Going to prepare to send wakeup msg to %i, %d \n", condArray[condID].outgoingMsgPktHdr.front().to, condArray[condID].outgoingMsgMailHdr.front().to); //DEBUG
		PacketHeader tempPktHdr;
		MailHeader tempMailHdr;
		tempPktHdr.to = condArray[condID].outgoingMsgPktHdr.front().to;
		tempPktHdr.from = condArray[condID].outgoingMsgPktHdr.front().from;
		tempMailHdr.to = condArray[condID].outgoingMsgMailHdr.front().to;
		//put headers in the queue
		lockArray[lockID].outgoingMsgPktHdr.push(tempPktHdr);
		lockArray[lockID].outgoingMsgMailHdr.push(tempMailHdr);
		
		//removing next owner from wait queue
		condArray[condID].outgoingMsgPktHdr.pop();
		condArray[condID].outgoingMsgMailHdr.pop();
		tempMailHdr.from = serverThread1BoxNum;
		
		//Send wakeup message
		/*char wakeup[maxMailSize];
		stringstream ssW (stringstream::in | stringstream::out);
		ssW << condArray[condID].lockUsed;
		ssW >> wakeup;
		tempMailHdr.length = strlen(wakeup) + 1;
		//printf("wakeup msg ready: ");  //DEBUG
		//printf("%s \n", wakeup); //DEBUG
		bool success = postOffice->Send(tempPktHdr, tempMailHdr, wakeup);
		if ( !success ) {
			printf("The postOffice Send failed. Terminating Nachos.\n");
			interrupt->Halt();
		} else {
			printf("Server sent wakeup message!\n");
		}*/
	}
	//set lockUsed to -1 if nobody is waiting
	if(condArray[condID].outgoingMsgPktHdr.empty()){
		condArray[condID].lockUsed = -1;
	}
	
	//send error code about signal back to sender
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorCode;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
	
	shouldSendMessage = 1;
	
	serverLockLock->Release();
	serverCVLock->Release();
	return;

}

void ServerDestroyCondition(char reply[], string &messageString, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){

	printf("Server: Destroy CV requested.\n");
	serverCVLock->Acquire();
	int condID = -1;
	
	for(int i = 0; i < MAX_CONDS; i++){
		if(condArray[i].name == messageString){
			condID = i;
			break;
		}
	}
	
	if(condID == -1){
		printf("error in deleting cv, no CV of that name!\n");
		serverCVLock->Release();
		interrupt->Halt();
	}
	
	int errorMessage = -1;
	if(condArray[condID].state == -1){
		printf("Error deleting cv that does not exist. \n");
	}else{
		condArray[condID].state = -1;
		errorMessage = 0;
	}
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorMessage;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	
	serverCVLock->Release();
	return;
}

void CreateMonitor_Syscall(char reply[], string name, int value, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: Create MV requested.\n");
	serverMVLock->Acquire();
	int index = -1;
	for(int i = 0; i < MAX_MONITORS; i++){ //check for a free one
		if(serverMonitorVariables[i].inUse == 0){
			index = i;
			break;
		}
	}
	
	for(int i = 0; i < MAX_MONITORS; i++){
		if(serverMonitorVariables[i].name == name){  //MV with requested name already exists, don't initialize anything, just return the index
			index = i;
			printf("monitor %s already exists!\n", name.c_str());
			if(serverMonitorVariables[index].inUse == 0){
				serverMonitorVariables[index].inUse = 1;
			}
			
			stringstream ssR (stringstream::in | stringstream::out);
			ssR << index;
			ssR >> reply;
			ssR.flush();
			
			outPktHdr.to = inPktHdr.from;
			outPktHdr.from = currentThread->getMachineId();
			outMailHdr.to = inMailHdr.from;
			outMailHdr.length = strlen(reply) + 1;
	
			shouldSendMessage = 1;
	
			serverMVLock->Release();
			
			return;
		}
	}
	if(index == -1){
		printf("no monitors available for use!\n");
		serverMVLock->Release();
		interrupt->Halt();
		return;
	} else {
		serverMonitorVariables[index].name = name;
		serverMonitorVariables[index].inUse = 1;
		//serverMonitorVariables[index].ownerMachineID = ownerMachineID;
		//serverMonitorVariables[index].ownerMailboxNum = ownerMailboxNum;
		serverMonitorVariables[index].monitorValues[serverMonitorVariables[index].curIndex] = value;
		serverMonitorVariables[index].curIndex++;
		
		for(int i = 0; i < MAX_MONITOR_VALUES; i++){
			serverMonitorVariables[index].monitorValues[i] = value;
		}
	}
	
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << index;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
	
	shouldSendMessage = 1;
	
	serverMVLock->Release();
	return;
}

void DestroyMonitor_Syscall(char reply[], string name, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: Destroy MV requested.\n");
	serverMVLock->Acquire();
	int monitorIndex = -1;
	for(int i = 0; i < MAX_MONITORS; i++){
		if(serverMonitorVariables[i].name == name){
			monitorIndex = i;
			break;
		}
	}
	
	if(monitorIndex == -1){
		printf("error in destroying monitor, does not exist!\n");
		serverMVLock->Release();
		interrupt->Halt();
	}
	
	int errorMessage = 0;
	if(monitorIndex < 0 || monitorIndex > MAX_MONITORS){
		printf("invalid monitor index %i in destroying monitor!\n", monitorIndex);
		errorMessage = -1;
		serverMVLock->Release();
		return;
	}
	serverMonitorVariables[monitorIndex].name = "";
	serverMonitorVariables[monitorIndex].inUse = 0;
	//serverMonitorVariables[index].ownerMachineID = -1;
	//serverMonitorVariables[index].ownerMailboxNum = -1;
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorMessage;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
	
	shouldSendMessage = 1;
	
	serverMVLock->Release();
	return;
}

void GetMonitor_Syscall(char reply[], int pos, string mvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: Get MV requested.\n");
	serverMVLock->Acquire();
	int monitorIndex = -1;
	for(int i = 0; i < MAX_MONITORS; i++){
		if(serverMonitorVariables[i].name == mvName){
			monitorIndex = i;
			break;
		}
	}
	
	if(monitorIndex == -1){
		printf("error in getting monitor, does not exist!\n");
		serverMVLock->Release();
		interrupt->Halt();
	}
	
	if(monitorIndex < 0 || monitorIndex > MAX_MONITORS){
		printf("invalid monitor index %i in getting monitor!\n", monitorIndex);
		serverMVLock->Release();
		return;
	}
	if(serverMonitorVariables[monitorIndex].inUse == 0){
		printf("Error accessing MV that doesn't exist!\n");
		serverMVLock->Release();
		return;
	}
	printf("Value on monitor %s position %i: %i\n", mvName.c_str(), pos, serverMonitorVariables[monitorIndex].monitorValues[pos]);
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << serverMonitorVariables[monitorIndex].monitorValues[pos];
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
	
	shouldSendMessage = 1;
	
	serverMVLock->Release();
	return;
}

// syscall, monitor index, value, position
void SetMonitor_Syscall(char reply[], int val, int pos, string mvName, PacketHeader inPktHdr, MailHeader inMailHdr, PacketHeader &outPktHdr, MailHeader &outMailHdr, int &shouldSendMessage){
	printf("Server: Set MV requested.\n");
	serverMVLock->Acquire();
	int monitorIndex = -1;
	for(int i = 0; i < MAX_MONITORS; i++){
		if(serverMonitorVariables[i].name == mvName){
			monitorIndex = i;
			break;
		}
	}
	
	if(monitorIndex == -1){
		printf("error in setting monitor does not exist!\n");
		serverMVLock->Release();
		interrupt->Halt();
	}
	
	int errorCode = 0;
	if(monitorIndex < 0 || monitorIndex > MAX_MONITORS){
		printf("invalid monitor index %i in setting monitor!\n", monitorIndex);
		serverMVLock->Release();
		return;
	}
	if(serverMonitorVariables[monitorIndex].inUse == 0){
		printf("Error accessing MV that doesn't exist!\n");
		errorCode = -1;
		serverMVLock->Release();
		return;
	}
	printf("Setting MV %s position %i with value %i\n", mvName.c_str(), pos, val);
	serverMonitorVariables[monitorIndex].monitorValues[pos] = val;
	stringstream ssR (stringstream::in | stringstream::out);
	ssR << errorCode;
	ssR >> reply;
	ssR.flush();
	
	outPktHdr.to = inPktHdr.from;
	outPktHdr.from = currentThread->getMachineId();
	outMailHdr.to = inMailHdr.from;
	outMailHdr.length = strlen(reply) + 1;
		
	shouldSendMessage = 1;
	
	serverMVLock->Release();
	return;
}
